package com.rustic.server.service.impl;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.RandomUtil;
import cn.xy.base.server.config.AppConfig;
import cn.xy.commons.cache.CacheManager;
import cn.xy.commons.exception.JzRuntimeException;
import cn.xy.third.sms.EmailService;
import cn.xy.third.sms.SmsService;
import cn.xy.third.sms.aliyun.AliyunConfig;
import cn.xy.third.sms.aliyun.SmsTemplate;
import cn.xy.third.sms.enums.CaptchaType;
import com.rustic.server.service.CaptchaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 验证码发送实现
 *
 *  @author xy
 */

@Slf4j
@Service
public class CaptchaServiceImpl implements CaptchaService {

    private static final int CAPTCHA_LENGTH = 6;
    private static final int RETRY_TIME = 60;
    private static final int CAPTCHA_TIME = 60 * 5;
    private static final String RETRY_KEY = "retry";
    private static final String CAPTCHA_KEY = "captcha";

    @Autowired
    private CacheManager cacheManager;

    @Autowired
    private AliyunConfig aliyunConfig;

    @Autowired
    private SmsService smsService;

    @Autowired
    private EmailService emailService;

    @Autowired
    private AppConfig appConfig;

    private static final String TEST_CAPTCHA = "369852";

    private static final String PROD = "prod";

    private static final String DEFAULT_TEMPLATE_NAME = "通用验证码";

    @Override
    public void sendSmsCaptcha(CaptchaType type, String mobile) {
        this.sendSmsCaptcha(type, mobile, DEFAULT_TEMPLATE_NAME);
    }

    @Override
    public void sendSmsCaptcha(CaptchaType type, String mobile, String templateName) {
        // 生成验证码
        String captcha = this.saveCaptchaToRedis(type, mobile);
        // 发送短信
        SmsTemplate template = aliyunConfig.getTemplateByName(templateName);
        if (template == null || CharSequenceUtil.isEmpty(template.getTemplateCode())) {
            throw new JzRuntimeException("验证码相关功能尚未启用");
        }
        Map<String, String> templateParam = new HashMap<>(1);
        templateParam.put("code", captcha);
        boolean result = smsService.sendSms(mobile, aliyunConfig.getSign(), template.getTemplateCode(), templateParam);
        if (!result) {
            throw new JzRuntimeException("验证码发送失败");
        }
    }

    @Override
    public void sendEmailCaptcha(CaptchaType type, String email) {
        this.sendEmailCaptcha(type, email, DEFAULT_TEMPLATE_NAME);
    }

    @Override
    public void sendEmailCaptcha(CaptchaType type, String email, String templateName) {
        // 生成验证码
        String captcha = this.saveCaptchaToRedis(type, email);

        Map<String, String> templateParam = new HashMap<>(1);
        templateParam.put("code", captcha);
        // 发送邮件
        boolean result = emailService.sendEmail(email, templateName, templateParam);
        if (!result) {
            throw new JzRuntimeException("验证码发送失败");
        }
    }

    @Override
    public void checkCaptcha(CaptchaType type, String captcha, String account) {
        // 如果验证码是测试验证码并且不在正式环境不做验证
        if (TEST_CAPTCHA.equals(captcha) && !PROD.equals(appConfig.getEnv())) {
            return;
        }
        Object backups = cacheManager.get(CAPTCHA_KEY + type.getValue() + account);
        if (backups == null) {
            throw new JzRuntimeException("验证码已失效或已过期");
        }
        if (!String.valueOf(backups).equals(captcha)) {
            throw new JzRuntimeException("验证码错误");
        }
    }

    @Override
    public String getAuthorizationCode(CaptchaType captchaType, int userId) {
        String retryKey = RETRY_KEY + userId;
        Object retry = cacheManager.get(retryKey);
        if (retry != null) {
            throw new JzRuntimeException("授权码获取频繁，请稍后重试");
        }
        // 保存到缓存中
        String key = captchaType.getValue() + UUID.randomUUID();
        cacheManager.set(retryKey, userId, RETRY_TIME);
        cacheManager.set(key, userId, RETRY_TIME);
        return key;
    }

    /**
     * 生成并将验证码保存到缓存中
     *
     * @param type    type
     * @param account account
     * @return captcha
     */
    private String saveCaptchaToRedis(CaptchaType type, String account) {
        String retryKey = RETRY_KEY + account;
        String captchaKey = CAPTCHA_KEY + type.getValue() + account;
        // 是否频繁获取
        Object retry = cacheManager.get(retryKey);
        if (retry != null) {
            throw new JzRuntimeException("验证码获取频繁，请稍后重试");
        }
        // 保存到缓存中
        String captcha = RandomUtil.randomNumbers(CAPTCHA_LENGTH);
        cacheManager.set(retryKey, account, RETRY_TIME);
        cacheManager.set(captchaKey, captcha, CAPTCHA_TIME);
        log.info("key: {} 验证码: {}", captchaKey, captcha);
        return captcha;
    }

}
